"""Generates the pins file for the SWM341"""
import re
import sys
import argparse


class Pin:
    """Holds the information associated with a pin."""
    def __init__(self, name, port, gpio, pbit, IRQn):
        self.name = name
        self.port = port
        self.gpio = gpio
        self.pbit = pbit
        self.afs  = []
        self.IRQn = IRQn

    def print(self):
        print('const pin_af_t pin_%s_af[] = {' %self.name)
        for af in self.afs:
            print('    AF(%-16s, %s),' %af)
        print('};\n')
        print('pin_obj_t pin_{:4s} = PIN({:4s}, {:5s}, {:5s}, {:5s}, pin_{:s}_af, {:10s});\n'.format(self.name, self.name, self.port, self.gpio, self.pbit, self.name, self.IRQn))

    def print_header(self, hdr_file):
        hdr_file.write('extern const pin_af_t pin_{:s}_af[];\n'.format(self.name))
        hdr_file.write('extern pin_obj_t pin_{:4s};\n'.format(self.name))


class Pins:
    def __init__(self):
        self.pins = {}   # list of Pin

    def parse_af_file(self, filename):
        with open(filename, 'r', encoding='utf-8') as f:
            for line in f.readlines():
                match = re.match(r'#define PORT([ABCDEMN])_PIN(\d+)_(\w+)\s+(\d+)', line)
                if match:
                    name = 'P' + match.group(1) + match.group(2)

                    if name not in self.pins:
                        self.pins[name] = Pin(name, 'PORT'+match.group(1), 'GPIO'+match.group(1), 'PIN'+match.group(2), 'GPIO%s_IRQn' %match.group(1))

                    self.pins[name].afs.append((f'{name}_{match.group(3)}', match.group(4)))

    def print(self):
        for pin in self.pins.values():
            pin.print()
        print('')
        print('static const mp_rom_map_elem_t pins_locals_dict_table[] = {')
        for pin in self.pins.values():
            print('    {{ MP_ROM_QSTR(MP_QSTR_{:5s}),  MP_ROM_PTR(&pin_{:5s}) }},'.format(pin.name, pin.name))
        print('};')
        print('')
        print('MP_DEFINE_CONST_DICT(pins_locals_dict, pins_locals_dict_table);')
    
    def print_header(self, hdr_filename):
        with open(hdr_filename, 'w') as hdr_file:
            for pin in self.pins.values():
                pin.print_header(hdr_file)

    def print_qstr(self, qstr_filename):
        with open(qstr_filename, 'w') as qstr_file:
            for pin in self.pins.values():
                print('Q({})'.format(pin.name), file=qstr_file)
            
                for af in pin.afs:
                    print('Q({})'.format(af[0]), file=qstr_file)
    
    def print_af_const(self, af_const_filename):
        with open(af_const_filename, 'w') as af_const_file:
            for pin in self.pins.values():
                for af in pin.afs:
                    print('    { MP_ROM_QSTR(MP_QSTR_%-16s),  MP_ROM_INT(%-2s)},' %(af[0], af[1]), file=af_const_file)


def main():
    parser = argparse.ArgumentParser(
        prog="make-pins.py",
        usage="%(prog)s [options] [command]",
        description="Generate board specific pin file"
    )
    parser.add_argument(
        "-a", "--af",
        dest="af_filename",
        help="Specifies the alternate function file for the chip",
        default="chip/SWM341_port.h"
    )
    parser.add_argument(
        "-p", "--prefix",
        dest="prefix_filename",
        help="Specifies beginning portion of generated pins file",
        default="boards/SWM341_prefix.c"
    )
    parser.add_argument(
        "-q", "--qstr",
        dest="qstr_filename",
        help="Specifies name of generated qstr header file",
        default="build-SWM34SLite/pins_qstr.h"
    )
    parser.add_argument(
        "-r", "--hdr",
        dest="hdr_filename",
        help="Specifies name of generated pin header file",
        default="build-SWM34SLite/pins.h"
    )
    parser.add_argument(
        "--af-const",
        dest="af_const_filename",
        help="Specifies header file for alternate function constants.",
        default="build-SWM34SLite/pins_af_const.h"
    )
    args = parser.parse_args(sys.argv[1:])

    pins = Pins()

    print('// This file was automatically generated by make-pins.py')
    print('//')

    if args.af_filename:
        print('// --af {:s}'.format(args.af_filename))
        pins.parse_af_file(args.af_filename)

    if args.prefix_filename:
        print('// --prefix {:s}'.format(args.prefix_filename))
        print('')
        with open(args.prefix_filename, 'r') as prefix_file:
            print(prefix_file.read())

    pins.print()
    pins.print_qstr(args.qstr_filename)
    pins.print_header(args.hdr_filename)
    pins.print_af_const(args.af_const_filename)


if __name__ == "__main__":
    main()
